#pragma once
#include <iostream>
#include <queue>
#include <vector>
#include <pthread.h>
#include "thread.hpp"
#include "Mutex.hpp"

using namespace Thread;
static const int gnum = 5;

template<class T>
class ThreadPool;

template <class T>
class ThreadPoolData{
public:
    std::string  _thread_name;
    ThreadPool<T>* _this;
    ThreadPoolData(const std::string& s ,ThreadPool<T>* __this ) : _thread_name(s),_this(__this)
        {}
};

template <class T>
class ThreadPool{
private:
    static void* task_routine(void * args){
        ThreadPoolData<T>* tpd = static_cast<ThreadPoolData<T>*>(args);
        while(true){
            T t;
            {
                LockGuard guard(tpd->_this->get_mutex_adress());
                while (tpd->_this->isQueueEmpty())  tpd->_this->CondtionWait();
                t = tpd->_this->pop();
            }
            std::cout<<tpd->_thread_name<<"接收到任务"<<t.tostring()<<"处理并完成了任务"<<t()<<std::endl;
        }
        delete tpd;
        return nullptr;
    }
private:
    T pop(){
        T t = _task_queue.front();
        _task_queue.pop();
        return t;
    }
    void lock(){
        pthread_mutex_lock(&_lock);
    }
    void unlock(){
        pthread_mutex_unlock(&_lock);
    }
    bool isQueueEmpty(){
        return _task_queue.empty();
    }
    void CondtionWait(){
        pthread_cond_wait(&_cond,&_lock);
    }
    pthread_mutex_t* get_mutex_adress(){
        return &_lock;
    }
public:
    ThreadPool(const int& num = gnum) :_threadsnum(num),_threads(num)
    {
        pthread_mutex_init(&_lock,nullptr);
        pthread_cond_init(&_cond,nullptr);
        for(int i = 0; i < num ; i++){
            _threads[i] = new thread();
        }
    }

    void run(){
        for(const auto& x : _threads){
            ThreadPoolData<T>* tpd = new ThreadPoolData<T>(x->getname(),this);
            x->start(task_routine,tpd);
        }
    }

    void push(const T& in){
        LockGuard guard(get_mutex_adress());
        _task_queue.push(in);
        pthread_cond_signal(&_cond);
    }

    ~ThreadPool(){
        pthread_mutex_destroy(&_lock);
        pthread_cond_destroy(&_cond);
        for(const auto& x : _threads) delete x;
    }

private:
    std::queue<T> _task_queue;
    std::vector<thread*> _threads;
    int _threadsnum;
    pthread_mutex_t _lock; //同一个队列不允许同时push和pop数据，因为会造成数据竞争而出错
    pthread_cond_t _cond;
};